#include "dtsu666.h"
#include "bsp.h"

Type_DTSU666_Def DTSU666 = {
    .com.slave_id = 1,
    .com.port = 1,
    .com.speed = 9600,

    .isInitOk = false,
};

/************************************************************/
void xp_dtsu666_read_thread(void *arg);
static int xp_dtsu666_debug(char *type,char *fun,char *param);

int xp_dtsu666_read_version(Type_DTSU666_Def * const handle);
int xp_dtsu666_read_phase_U_I(Type_DTSU666_Def * const handle);
int xp_dtsu666_read_ImpEp(Type_DTSU666_Def * const handle);
int xp_dtsu666_read_ExpEp(Type_DTSU666_Def * const handle);
int xp_dtsu666_read_Pt(Type_DTSU666_Def * const handle);
int xp_dtsu666_read_Qt(Type_DTSU666_Def * const handle);
int xp_dtsu666_clear_Ep(Type_DTSU666_Def * const handle);

int xp_dtsu666_write_reginster(Type_DTSU666_Def * const handler, uint16_t addr, uint16_t *data, uint8_t len);
int xp_dtsu666_read_reginster(Type_DTSU666_Def * const handler, uint16_t addr, uint16_t read_len, uint8_t *rec_data, uint8_t *rec_len);

int32_t xp_dtsu666_read_creat_params(char *pKeyStr, int32_t defaultValue);
void memcpy_resv_word(void *des, void * const res, uint16_t size);
void xp_dtsu666_show(void);



int xp_dtsu666_init(void)
{
	int ret = 0;
		
	//初始化端口modbus
	ret = xp_modbus_init(DTSU666.com.port, DTSU666.com.speed, MB_PAR_NONE, 100);
	
	if(0 != ret){
		println("DTUS666 sens <id:%d> modbus init fail ! ret = %d", DTSU666.com.slave_id, ret);
		return ret;
	}else if ( 0 == (ret = xp_dtsu666_read_version(&DTSU666)) ){
        DTSU666.isInitOk = true;
		println("DTUS666 sens <id:%d> init success, version: %X", DTSU666.version);
	}else{
		println("DTUS666 sens <id:%d> modbus init success, but read data failed ! ret = %d", DTSU666.com.slave_id, ret);
	}

    if (DTSU666.isInitOk){
        //电表参数读取线程
        if (0 != aos_task_new("xp_dtsu666_read_thread", xp_dtsu666_read_thread, NULL, 2048)){
            return -1;
        }

        DTSU666.logTime = xp_dtsu666_read_creat_params("dtsu_logtime", 5000);
    }
    xp_cli_debug_add(xp_dtsu666_debug);
    return ret;
}

void xp_dtsu666_read_thread(void *arg)
{
    int ret;
    uint32_t timeStamp = 0;

    for (;;)
    {
        ret = xp_dtsu666_read_phase_U_I(&DTSU666);
        ret += xp_dtsu666_read_ImpEp(&DTSU666);
        //ret += xp_dtsu666_read_ExpEp(&DTSU666);

        if (DTSU666.logTime && 0 == ret && aos_now_ms() - timeStamp > DTSU666.logTime){
            timeStamp = aos_now_ms();
            xp_dtsu666_show();
        }

        aos_msleep(1000);
    }
    
}
//读取版本号
int xp_dtsu666_read_version(Type_DTSU666_Def * const handle)
{
    int ret = xp_dtsu666_read_reginster(handle, ADDR_REV, 1, handle->com.rec_data, &handle->com.rec_len);
	if (0 == ret){
		handle->version = (handle->com.rec_data[0] << 8) | handle->com.rec_data[1];
        return 0;
	}
    return -1;
}
//读取各相电压及电流
int xp_dtsu666_read_phase_U_I(Type_DTSU666_Def * const handle)
{
	float tmpBuf[6];
    int ret = xp_dtsu666_read_reginster(handle, ADDR_Ua, 2 * 6, handle->com.rec_data, &handle->com.rec_len);
	if (0 == ret){
		memcpy_resv_word(tmpBuf, handle->com.rec_data, handle->com.rec_len);
		DTSU666.param.Ua = tmpBuf[0] * 0.1f;
		DTSU666.param.Ub = tmpBuf[1] * 0.1f;
		DTSU666.param.Uc = tmpBuf[2] * 0.1f;
		
		DTSU666.param.Ia = tmpBuf[3] * 0.001f;
		DTSU666.param.Ib = tmpBuf[4] * 0.001f;
		DTSU666.param.Ic = tmpBuf[5] * 0.001f;
        return 0;
	}
    return -1;
}
//读取正向有功总电能
int xp_dtsu666_read_ImpEp(Type_DTSU666_Def * const handle)
{
    int ret = xp_dtsu666_read_reginster(handle, ADDR_ImpEp, 2, handle->com.rec_data, &handle->com.rec_len);
	if (0 == ret){
		memcpy_resv_word(&DTSU666.param.ImpEp, handle->com.rec_data, handle->com.rec_len);
        return 0;
	}
    return -1;
}
//读取反向有功总电能
int xp_dtsu666_read_ExpEp(Type_DTSU666_Def * const handle)
{
    int ret = xp_dtsu666_read_reginster(handle, ADDR_ExpEp, 2, handle->com.rec_data, &handle->com.rec_len);
	if (0 == ret){
        memcpy_resv_word(&DTSU666.param.ExpEp, handle->com.rec_data, handle->com.rec_len);
        return 0;
	}
    return -1;
}
//读取合相有功功率
int xp_dtsu666_read_Pt(Type_DTSU666_Def * const handle)
{
    int ret = xp_dtsu666_read_reginster(handle, ADDR_Pt, 2, handle->com.rec_data, &handle->com.rec_len);
	if (0 == ret){
		float tmp;
        memcpy_resv_word(&tmp, handle->com.rec_data, handle->com.rec_len);
		DTSU666.param.Pt = tmp * 0.1f;
        return 0;
	}
    return -1;
}
//读取合相无功功率
int xp_dtsu666_read_Qt(Type_DTSU666_Def * const handle)
{
    int ret = xp_dtsu666_read_reginster(handle, ADDR_Qt, 2, handle->com.rec_data, &handle->com.rec_len);
	if (0 == ret){
		float tmp;
        memcpy_resv_word(&tmp, handle->com.rec_data, handle->com.rec_len);
		DTSU666.param.Qt = tmp * 0.1f;
        return 0;
	}
    return -1;
}
//置零电能数据
int xp_dtsu666_clear_Ep(Type_DTSU666_Def * const handle)
{
    uint16_t data = 1;
    int ret = xp_dtsu666_write_reginster(handle, ADDR_CLR_E, &data, 1);
	if (0 == ret){
        return 0;
	}
    return -1;
}
//保持写寄存器
int xp_dtsu666_write_reginster(Type_DTSU666_Def * const handler, uint16_t addr, uint16_t *data, uint8_t len)
{
    int sta = 0;
    MB_data modbus;
    uint8_t try_times = 3;

    modbus.slave_id = handler->com.slave_id;
    modbus.mb_fun = mb_hold_w;
    modbus.start_addr = addr;
    modbus.wBuf = data;
    modbus.rwLen = len;
    modbus.resBuf = handler->com.rec_data;
    modbus.resLen = &handler->com.rec_len;
    while(try_times--){
        if( 0 == xp_modbus_ask(handler->com.port, &modbus) ) return 0;
    }

    return -1;
}
//保持读寄存器
int xp_dtsu666_read_reginster(Type_DTSU666_Def * const handler, uint16_t addr, uint16_t read_len, uint8_t *rec_data, uint8_t *rec_len)
{
    int sta = 0;
    MB_data modbus;
    uint8_t try_times = 3;

    modbus.slave_id = handler->com.slave_id;
    modbus.mb_fun = mb_hold_r;
    modbus.start_addr = addr;
    modbus.rwLen = read_len;
    modbus.resBuf = rec_data;
    modbus.resLen = rec_len;
    while(try_times--){
        if( 0 == xp_modbus_ask(handler->com.port, &modbus) ) return 0;
    }
	println("dtsu666 read fail !!!");
    return -1;
}
//带大小端转换的memcpy  __REVSH
void memcpy_resv_word(void *des, void * const res, uint16_t size)
{
	for (uint16_t i = 0; i < size; i += sizeof(uint32_t)){
		*((uint8_t *)des + i + 0) = *((uint8_t *)res + i + 3);
		*((uint8_t *)des + i + 1) = *((uint8_t *)res + i + 2);
		*((uint8_t *)des + i + 2) = *((uint8_t *)res + i + 1);
		*((uint8_t *)des + i + 3) = *((uint8_t *)res + i + 0);
	}
}
//读取参数,如果不存在则创建,并设置为默认值
int32_t xp_dtsu666_read_creat_params(char *pKeyStr, int32_t defaultValue)
{
	char buf[15] = {0};
	int len = sizeof(buf);
	
	if (NULL != pKeyStr){
		uint8_t tryTimes = 3;
		while(tryTimes--){
			if (0 != aos_kv_get(pKeyStr, buf, &len)){
				println("Read kv fail. <%s>  tryTime %d\r\n", pKeyStr, 3 - tryTimes);
			}else{
				return atoi(buf);
			}
		}
		
		sprintf(buf, "%d", defaultValue);
		tryTimes = 3;
		
		while(tryTimes--){
			if( 0 != aos_kv_set(pKeyStr, buf, strlen(buf), 1) ){
				println("Update kv fail. <%s>  tryTime %d\r\n", pKeyStr, 3 - tryTimes);
			}else{
                println("Creat key: %s value: %d OK\r\n", pKeyStr, defaultValue);
				return defaultValue;
			}
		}
	}
	return defaultValue;
}
//输出各参数
void xp_dtsu666_show(void)
{
	println("Ua: %.2f Ub: %.2f Uc: %.2f\r\n", DTSU666.param.Ua, DTSU666.param.Ub, DTSU666.param.Uc);
    println("Ia: %.2f Ib: %.2f Ic: %.2f\r\n", DTSU666.param.Ia, DTSU666.param.Ib, DTSU666.param.Ic);
    println("Pt: %.2f Qt: %.2f\r\n", DTSU666.param.Pt, DTSU666.param.Qt);
    println("ImpEp: %.2f ExpEp: %.2f\r\n", DTSU666.param.ImpEp, DTSU666.param.ExpEp);
}
//调试接口
static int xp_dtsu666_debug(char *type,char *fun,char *param)
{
	int ret = -1;
	
	//本调试接口仅支持 "dtsu666_" 起始的命令
	if (NULL == strstr(type, "dtsu666_")){
		return 0;
	}else{
		type += strlen("dtsu666_");
	}
    //xp dtsu666_show  打印所测量信息
	if (strcasecmp(type, "Show") == 0){
		xp_dtsu666_show();
	}
	else if (strcasecmp(type, "clear") == 0){
        println("Clear %s\r\n", DTSU666.isInitOk && (0 == xp_dtsu666_clear_Ep(&DTSU666)) ? ("Success") : ("Fail"));
    }
    else if (strcasecmp(type, "logTime") == 0){
        println("Set logTime = %d\r\n", DTSU666.logTime = atoi(fun));
    }
    else {
        return 0;
    }
    return 1;
}